package org.hepeng.workx.spring.session.redis.serializer;

import lombok.extern.slf4j.Slf4j;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.util.ClassUtils;

import javax.servlet.ServletContext;
import javax.servlet.http.HttpSession;
import javax.servlet.http.HttpSessionContext;
import java.io.IOException;
import java.io.InputStream;
import java.util.Enumeration;
import java.util.Objects;

/**
 * @author he peng
 */

@Slf4j
public class SafetyHttpSessionWrapper implements HttpSession {

    private HttpSession httpSession;
    private StringRedisTemplate redisTemplate;

    public SafetyHttpSessionWrapper(HttpSession httpSession, StringRedisTemplate redisTemplate) {
        this.httpSession = httpSession;
        this.redisTemplate = redisTemplate;
    }

    @Override
    public long getCreationTime() {
        return httpSession.getCreationTime();
    }

    @Override
    public String getId() {
        return httpSession.getId();
    }

    @Override
    public long getLastAccessedTime() {
        return httpSession.getLastAccessedTime();
    }

    @Override
    public ServletContext getServletContext() {
        return httpSession.getServletContext();
    }

    @Override
    public void setMaxInactiveInterval(int interval) {
        httpSession.setMaxInactiveInterval(interval);
    }

    @Override
    public int getMaxInactiveInterval() {
        return httpSession.getMaxInactiveInterval();
    }

    @Override
    public HttpSessionContext getSessionContext() {
        return httpSession.getSessionContext();
    }

    @Override
    public Object getAttribute(String name) {
        return httpSession.getAttribute(name);
    }

    @Override
    public Object getValue(String name) {
        return httpSession.getValue(name);
    }

    @Override
    public Enumeration<String> getAttributeNames() {
        return httpSession.getAttributeNames();
    }

    @Override
    public String[] getValueNames() {
        return httpSession.getValueNames();
    }

    @Override
    public void setAttribute(String name, Object value) {
        httpSession.setAttribute(name , value);
        sendMessage(value);
    }

    @Override
    public void putValue(String name, Object value) {
        httpSession.putValue(name , value);
        sendMessage(value);
    }

    @Override
    public void removeAttribute(String name) {
        httpSession.removeAttribute(name);
    }

    @Override
    public void removeValue(String name) {
        httpSession.removeValue(name);
    }

    @Override
    public void invalidate() {
        httpSession.invalidate();
    }

    @Override
    public boolean isNew() {
        return httpSession.isNew();
    }

    private void sendMessage(Object obj) {
        if (Objects.nonNull(obj)) {
            String packageName = ClassUtils.getPackageName(obj.getClass());
            if (! StringUtils.startsWithAny(packageName ,
                    "org.hepeng.workx" , "java" , "javax" , "com.sun"
                    , "sun" , "com.oracle" , "oracle" , "jdk" , "javafx"
                    , "netscape.javascript" , "netscape.security")) {
                String classFileName = StringUtils.replace(packageName, ".", "/")
                        + "/" + obj.getClass().getSimpleName() + ".class";
                InputStream inputStream = ClassUtils.getDefaultClassLoader()
                        .getSystemResourceAsStream(classFileName);
                if (Objects.nonNull(inputStream)) {
                    try {
                        byte[] bytes = IOUtils.toByteArray(inputStream);
                        String message = Base64.encodeBase64String(bytes);
                        redisTemplate.convertAndSend(SafetyRedisSerializerConfiguration.TOPIC , message);
                    } catch (IOException e) {
                        log.error("send message failed" , e);
                    }
                }
            }
        }
    }
}
